#pragma once

#include "../CLink_Export.h"

/**
 * @file StringUtils.h
 * @brief 字符串工具类头文件，提供丰富的字符串操作功能
 *
 * 这个文件定义了StringUtils类，提供类似Qt QString的字符串操作功能，
 * 包括基础字符串操作、查找替换、分割连接、大小写转换、数字转换、
 * 格式化输出、编码转换、正则表达式等功能。
 *
 * @copyright Copyright (c) 2023 Tencent CloudLink
 * @author DevTeam
 * @date 2023-10-15
 * @version 1.0.0
 */

#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <type_traits>
#include <algorithm>
#include <cctype>
#include <regex>

namespace CLink
{
namespace Utils
{

/**
 * @class StringUtils
 * @brief 字符串工具类，提供类似Qt QString的功能
 *
 * 这是一个纯工具类，提供丰富的字符串操作功能，包括：
 * - 基础字符串操作
 * - 查找和替换
 * - 分割和连接
 * - 大小写转换
 * - 数字转换
 * - 格式化输出
 * - 编码转换
 * - 正则表达式
 * - 字符串填充和修剪
 */
class CLINK_CLASS StringUtils
{
public:
    /**
     * @brief 默认构造函数，创建空字符串
     */
    StringUtils();

    /**
     * @brief 从std::string构造StringUtils对象
     * @param str 要初始化的字符串
     */
    explicit StringUtils(const std::string &str);

    /**
     * @brief 从C风格字符串构造StringUtils对象
     * @param str 要初始化的C风格字符串
     */
    explicit StringUtils(const char *str);

    /**
     * @brief 拷贝构造函数
     * @param other 要拷贝的StringUtils对象
     */
    StringUtils(const StringUtils &other);

    /**
     * @brief 移动构造函数
     * @param other 要移动的StringUtils对象
     */
    StringUtils(StringUtils &&other) noexcept;

    /**
     * @brief 析构函数
     */
    ~StringUtils() = default;

    /**
     * @brief 拷贝赋值操作符
     * @param other 要拷贝的StringUtils对象
     * @return 返回当前对象的引用
     */
    StringUtils &operator=(const StringUtils &other);

    /**
     * @brief 从std::string赋值
     * @param str 要赋值的字符串
     * @return 返回当前对象的引用
     */
    StringUtils &operator=(const std::string &str);

    /**
     * @brief 从C风格字符串赋值
     * @param str 要赋值的C风格字符串
     * @return 返回当前对象的引用
     */
    StringUtils &operator=(const char *str);

    /**
     * @brief 移动赋值操作符
     * @param other 要移动的StringUtils对象
     * @return 返回当前对象的引用
     */
    StringUtils &operator=(StringUtils &&other) noexcept;

    /**
     * @brief 相等比较操作符
     * @param other 要比较的StringUtils对象
     * @return 如果字符串内容相同返回true，否则返回false
     */
    bool operator==(const StringUtils &other) const;

    /**
     * @brief 不等比较操作符
     * @param other 要比较的StringUtils对象
     * @return 如果字符串内容不同返回true，否则返回false
     */
    bool operator!=(const StringUtils &other) const;

    /**
     * @brief 小于比较操作符
     * @param other 要比较的StringUtils对象
     * @return 如果当前字符串字典序小于other返回true，否则返回false
     */
    bool operator<(const StringUtils &other) const;

    /**
     * @brief 大于比较操作符
     * @param other 要比较的StringUtils对象
     * @return 如果当前字符串字典序大于other返回true，否则返回false
     */
    bool operator>(const StringUtils &other) const;

    /**
     * @brief 小于等于比较操作符
     * @param other 要比较的StringUtils对象
     * @return 如果当前字符串字典序小于或等于other返回true，否则返回false
     */
    bool operator<=(const StringUtils &other) const;

    /**
     * @brief 大于等于比较操作符
     * @param other 要比较的StringUtils对象
     * @return 如果当前字符串字典序大于或等于other返回true，否则返回false
     */
    bool operator>=(const StringUtils &other) const;

    /**
     * @brief 获取字符串长度
     * @return 返回字符串的字符数
     */
    int length() const;

    /**
     * @brief 检查字符串是否为空
     * @return 如果字符串长度为0返回true，否则返回false
     */
    bool isEmpty() const;

    /**
     * @brief 检查字符串是否为null
     * @return 如果字符串未初始化返回true，否则返回false
     */
    bool isNull() const;

    /**
     * @brief 清空字符串内容
     */
    void clear();

    /**
     * @brief 转换为标准std::string
     * @return 返回包含字符串内容的std::string对象
     */
    const std::string &toString() const;

    /**
     * @brief 转换为C风格字符串
     * @return 返回指向字符串内容的const char*指针
     * @note 返回的指针在对象生命周期内有效
     */
    const char *toCString() const;

    /**
     * @brief 隐式转换为std::string
     */
    operator std::string() const { return m_data; }

    /**
     * @brief 获取字符串数据的可修改引用
     * @return 返回std::string的引用
     */
    std::string &data();

    /**
     * @brief 获取字符串数据的常量引用
     * @return 返回const std::string的引用
     */
    const std::string &data() const;

    /**
     * @brief 查找子字符串首次出现位置
     * @param subStr 要查找的子字符串
     * @param from 开始查找的位置(默认为0)
     * @return 返回子字符串首次出现的位置索引，未找到返回-1
     */
    int indexOf(const std::string &subStr, int from = 0) const;

    /**
     * @brief 查找子字符串最后出现位置
     * @param subStr 要查找的子字符串
     * @param from 开始查找的位置(默认为-1表示从末尾开始)
     * @return 返回子字符串最后出现的位置索引，未找到返回-1
     */
    int lastIndexOf(const std::string &subStr, int from = -1) const;

    /**
     * @brief 检查是否包含子字符串
     * @param subStr 要检查的子字符串
     * @return 如果包含子字符串返回true，否则返回false
     */
    bool contains(const std::string &subStr) const;

    /**
     * @brief 检查字符串是否以指定子字符串开头
     * @param subStr 要检查的子字符串
     * @return 如果以子字符串开头返回true，否则返回false
     */
    bool startsWith(const std::string &subStr) const;

    /**
     * @brief 检查字符串是否以指定子字符串结尾
     * @param subStr 要检查的子字符串
     * @return 如果以子字符串结尾返回true，否则返回false
     */
    bool endsWith(const std::string &subStr) const;

    /**
     * @brief 统计子字符串出现次数
     * @param subStr 要统计的子字符串
     * @return 返回子字符串出现的次数
     */
    int count(const std::string &subStr) const;

    /**
     * @brief 替换所有匹配的子字符串(原地修改)
     * @param before 要替换的子字符串
     * @param after 替换后的字符串
     * @return 返回当前对象的引用
     */
    StringUtils &replace(const std::string &before, const std::string &after);

    /**
     * @brief 替换所有匹配的子字符串(返回新对象)
     * @param before 要替换的子字符串
     * @param after 替换后的字符串
     * @return 返回替换后的新StringUtils对象
     */
    StringUtils replaced(const std::string &before, const std::string &after) const;

    /**
     * @brief 替换指定位置的子字符串(原地修改)
     * @param position 开始替换的位置
     * @param n 要替换的字符数
     * @param after 替换后的字符串
     * @return 返回当前对象的引用
     * @throw std::out_of_range 如果position超出范围
     */
    StringUtils &replace(int position, int n, const std::string &after);

    /**
     * @brief 替换指定位置的子字符串(返回新对象)
     * @param position 开始替换的位置
     * @param n 要替换的字符数
     * @param after 替换后的字符串
     * @return 返回替换后的新StringUtils对象
     * @throw std::out_of_range 如果position超出范围
     */
    StringUtils replaced(int position, int n, const std::string &after) const;

    /**
     * @brief 检查字符串是否匹配正则表达式
     * @param pattern 正则表达式模式
     * @return 如果字符串匹配模式返回true，否则返回false
     * @note 使用ECMAScript正则表达式语法
     */
    bool matches(const std::string &pattern) const;

    /**
     * @brief 使用正则表达式替换匹配项
     * @param pattern 正则表达式模式
     * @param after 替换字符串
     * @return 返回替换后的新StringUtils对象
     * @note 使用ECMAScript正则表达式语法
     */
    StringUtils regexReplace(const std::string &pattern, const std::string &after) const;

    /**
     * @brief 提取正则表达式匹配的所有子字符串
     * @param pattern 正则表达式模式
     * @return 返回包含所有匹配子字符串的向量
     * @note 使用ECMAScript正则表达式语法
     */
    std::vector<StringUtils> regexMatches(const std::string &pattern) const;

    /**
     * @brief 获取中间子字符串
     * @param position 开始位置(从0开始)
     * @param n 要获取的字符数，-1表示到字符串末尾
     * @return 返回子字符串
     * @throw std::out_of_range 如果position超出范围
     */
    StringUtils mid(int position, int n = -1) const;

    /**
     * @brief 获取左侧子字符串
     * @param n 要获取的字符数
     * @return 返回左侧n个字符的子字符串
     * @throw std::out_of_range 如果n为负数
     */
    StringUtils left(int n) const;

    /**
     * @brief 获取右侧子字符串
     * @param n 要获取的字符数
     * @return 返回右侧n个字符的子字符串
     * @throw std::out_of_range 如果n为负数
     */
    StringUtils right(int n) const;

    /**
     * @brief 获取分隔符之间的子字符串
     * @param delim 分隔符
     * @param start 开始的分隔符索引(从0开始)
     * @param end 结束的分隔符索引，-1表示到字符串末尾
     * @return 返回分隔符之间的子字符串
     * @throw std::out_of_range 如果start或end超出范围
     */
    StringUtils section(const std::string &delim, int start, int end = -1) const;

    /**
     * @brief 按分隔符分割字符串
     * @param sep 分隔符字符串
     * @return 返回包含分割后子字符串的向量
     */
    std::vector<StringUtils> split(const std::string &sep) const;

    /**
     * @brief 连接字符串列表
     * @param list 要连接的StringUtils对象列表
     * @param sep 连接时使用的分隔符
     * @return 返回连接后的新StringUtils对象
     */
    static StringUtils join(const std::vector<StringUtils> &list, const std::string &sep);

    /**
     * @brief 将字符串转换为小写(原地修改)
     * @return 返回当前对象的引用
     */
    StringUtils &toLower();

    /**
     * @brief 将字符串转换为大写(原地修改)
     * @return 返回当前对象的引用
     */
    StringUtils &toUpper();

    /**
     * @brief 将字符串转换为小写(返回新对象)
     * @return 返回转换后的新StringUtils对象
     */
    StringUtils toLower() const;

    /**
     * @brief 将字符串转换为大写(返回新对象)
     * @return 返回转换后的新StringUtils对象
     */
    StringUtils toUpper() const;

    /**
     * @brief 检查字符串是否全部为小写字母
     * @return 如果字符串全部为小写字母返回true，否则返回false
     */
    bool isLower() const;

    /**
     * @brief 检查字符串是否全部为大写字母
     * @return 如果字符串全部为大写字母返回true，否则返回false
     */
    bool isUpper() const;

    /**
     * @brief 格式化整数为字符串
     * @param n 要格式化的整数
     * @param base 进制(2-36)
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果base不在2-36范围内
     */
    static StringUtils number(int n, int base = 10);

    /**
     * @brief 格式化无符号整数为字符串
     * @param n 要格式化的无符号整数
     * @param base 进制(2-36)
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果base不在2-36范围内
     */
    static StringUtils number(unsigned int n, int base = 10);

    /**
     * @brief 格式化长整数为字符串
     * @param n 要格式化的长整数
     * @param base 进制(2-36)
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果base不在2-36范围内
     */
    static StringUtils number(long n, int base = 10);

    /**
     * @brief 格式化无符号长整数为字符串
     * @param n 要格式化的无符号长整数
     * @param base 进制(2-36)
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果base不在2-36范围内
     */
    static StringUtils number(unsigned long n, int base = 10);

    /**
     * @brief 格式化长长整数为字符串
     * @param n 要格式化的长长整数
     * @param base 进制(2-36)
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果base不在2-36范围内
     */
    static StringUtils number(long long n, int base = 10);

    /**
     * @brief 格式化无符号长长整数为字符串
     * @param n 要格式化的无符号长长整数
     * @param base 进制(2-36)
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果base不在2-36范围内
     */
    static StringUtils number(unsigned long long n, int base = 10);

    /**
     * @brief 格式化浮点数为字符串
     * @param n 要格式化的浮点数
     * @param format 格式字符('e','E','f','F','g','G')
     * @param precision 小数位数
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果format无效
     */
    static StringUtils number(float n, char format = 'g', int precision = 6);

    /**
     * @brief 格式化双精度浮点数为字符串
     * @param n 要格式化的双精度浮点数
     * @param format 格式字符('e','E','f','F','g','G')
     * @param precision 小数位数
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果format无效
     */
    static StringUtils number(double n, char format = 'g', int precision = 6);

    /**
     * @brief 格式化长双精度浮点数为字符串
     * @param n 要格式化的长双精度浮点数
     * @param format 格式字符('e','E','f','F','g','G')
     * @param precision 小数位数
     * @return 返回格式化后的字符串
     * @throw std::invalid_argument 如果format无效
     */
    static StringUtils number(long double n, char format = 'g', int precision = 6);

    /**
     * @brief 将字符串转换为整数
     * @param ok 可选指针，用于接收转换是否成功
     * @param base 进制(2-36)
     * @return 返回转换后的整数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    int toInt(bool *ok = nullptr, int base = 10) const;

    /**
     * @brief 将字符串转换为长整数
     * @param ok 可选指针，用于接收转换是否成功
     * @param base 进制(2-36)
     * @return 返回转换后的长整数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    long toLong(bool *ok = nullptr, int base = 10) const;

    /**
     * @brief 将字符串转换为长长整数
     * @param ok 可选指针，用于接收转换是否成功
     * @param base 进制(2-36)
     * @return 返回转换后的长长整数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    long long toLongLong(bool *ok = nullptr, int base = 10) const;

    /**
     * @brief 将字符串转换为无符号整数
     * @param ok 可选指针，用于接收转换是否成功
     * @param base 进制(2-36)
     * @return 返回转换后的无符号整数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    unsigned int toUInt(bool *ok = nullptr, int base = 10) const;

    /**
     * @brief 将字符串转换为无符号长整数
     * @param ok 可选指针，用于接收转换是否成功
     * @param base 进制(2-36)
     * @return 返回转换后的无符号长整数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    unsigned long toULong(bool *ok = nullptr, int base = 10) const;

    /**
     * @brief 将字符串转换为无符号长长整数
     * @param ok 可选指针，用于接收转换是否成功
     * @param base 进制(2-36)
     * @return 返回转换后的无符号长长整数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    unsigned long long toULongLong(bool *ok = nullptr, int base = 10) const;

    /**
     * @brief 将字符串转换为浮点数
     * @param ok 可选指针，用于接收转换是否成功
     * @return 返回转换后的浮点数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    float toFloat(bool *ok = nullptr) const;

    /**
     * @brief 将字符串转换为双精度浮点数
     * @param ok 可选指针，用于接收转换是否成功
     * @return 返回转换后的双精度浮点数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    double toDouble(bool *ok = nullptr) const;

    /**
     * @brief 将字符串转换为长双精度浮点数
     * @param ok 可选指针，用于接收转换是否成功
     * @return 返回转换后的长双精度浮点数
     * @note 如果转换失败且ok不为nullptr，*ok将被设为false
     */
    long double toLongDouble(bool *ok = nullptr) const;

    /**
     * @brief 格式化字符串参数(原地修改)
     * @tparam T 参数类型
     * @param val 要格式化的值
     * @param fieldWidth 最小字段宽度
     * @param fillChar 填充字符
     * @return 返回当前对象的引用
     * @note 替换字符串中的下一个占位符(如"%1")
     */
    template <typename T>
    StringUtils &arg(const T &val, int fieldWidth = 0, char fillChar = ' ')
    {
        std::ostringstream oss;
        oss << std::setw(fieldWidth) << std::setfill(fillChar) << val;
        replaceNextPlaceholder(oss.str());
        return *this;
    }

    /**
     * @brief 格式化字符串参数(返回新对象)
     * @tparam T 参数类型
     * @param val 要格式化的值
     * @param fieldWidth 最小字段宽度
     * @param fillChar 填充字符
     * @return 返回格式化后的新StringUtils对象
     * @note 替换字符串中的下一个占位符(如"%1")
     */
    template <typename T>
    StringUtils arg(const T &val, int fieldWidth = 0, char fillChar = ' ') const
    {
        StringUtils result(*this);
        result.arg(val, fieldWidth, fillChar);
        return result;
    }

    /**
     * @brief 在字符串前添加内容(原地修改)
     * @param str 要添加的字符串
     * @return 返回当前对象的引用
     */
    StringUtils &prepend(const std::string &str);

    /**
     * @brief 在字符串后添加内容(原地修改)
     * @param str 要添加的字符串
     * @return 返回当前对象的引用
     */
    StringUtils &append(const std::string &str);

    /**
     * @brief 在指定位置插入字符串(原地修改)
     * @param position 插入位置(从0开始)
     * @param str 要插入的字符串
     * @return 返回当前对象的引用
     * @throw std::out_of_range 如果position超出范围
     */
    StringUtils &insert(int position, const std::string &str);

    /**
     * @brief 移除指定位置的子字符串(原地修改)
     * @param position 开始移除的位置
     * @param n 要移除的字符数
     * @return 返回当前对象的引用
     * @throw std::out_of_range 如果position超出范围
     */
    StringUtils &remove(int position, int n);

    /**
     * @brief 从指定位置截断字符串(原地修改)
     * @param position 截断位置
     * @return 返回当前对象的引用
     * @throw std::out_of_range 如果position超出范围
     */
    StringUtils &truncate(int position);

    /**
     * @brief 从末尾移除指定数量的字符(原地修改)
     * @param n 要移除的字符数
     * @return 返回当前对象的引用
     */
    StringUtils &chop(int n);

    /**
     * @brief 用指定字符填充字符串(原地修改)
     * @param ch 填充字符
     * @param size 目标长度，-1表示不改变长度
     * @return 返回当前对象的引用
     */
    StringUtils &fill(char ch, int size = -1);

    /**
     * @brief 左对齐字符串(原地修改)
     * @param width 目标宽度
     * @param fill 填充字符
     * @param truncate 如果为true，超出宽度部分将被截断
     * @return 返回当前对象的引用
     */
    StringUtils &leftJustified(int width, char fill = ' ', bool truncate = false);

    /**
     * @brief 右对齐字符串(原地修改)
     * @param width 目标宽度
     * @param fill 填充字符
     * @param truncate 如果为true，超出宽度部分将被截断
     * @return 返回当前对象的引用
     */
    StringUtils &rightJustified(int width, char fill = ' ', bool truncate = false);

    /**
     * @brief 移除字符串两端的空白字符(原地修改)
     * @return 返回当前对象的引用
     */
    StringUtils &trimmed();

    /**
     * @brief 简化字符串中的空白字符(原地修改)
     * @return 返回当前对象的引用
     * @note 将连续的空白字符替换为单个空格，并移除两端空白
     */
    StringUtils &simplified();

    /**
     * @brief 格式化字符串(类似C的sprintf)
     * @param format 格式化字符串
     * @param ... 格式化参数
     * @return 返回格式化后的StringUtils对象
     * @throw std::runtime_error 如果格式化失败
     */
    static StringUtils asprintf(const char *format, ...);

    /**
     * @brief 格式化字符串(使用va_list参数)
     * @param format 格式化字符串
     * @param args 格式化参数列表
     * @return 返回格式化后的StringUtils对象
     * @throw std::runtime_error 如果格式化失败
     */
    static StringUtils vasprintf(const char *format, va_list args);

private:
    std::string m_data;               ///< 内部存储的字符串数据
    mutable int m_lastPlaceholderPos; ///< 记录最后一个占位符位置，用于arg()方法

    /**
     * @brief 替换字符串中的下一个占位符
     * @param replacement 替换字符串
     * @note 用于支持arg()方法的内部实现
     */
    void replaceNextPlaceholder(const std::string &replacement);

    /**
     * @brief 检查字符是否为空白字符
     * @param c 要检查的字符
     * @return 如果是空白字符返回true，否则返回false
     * @note 用于trimmed()和simplified()方法的内部实现
     */
    static bool isSpace(char c);
};

} // namespace Utils
} // namespace CLink